package com.icongyou.enterprise.talent_analysis.service;

import com.icongyou.enterprise.data_aggregation.entity.*;
import com.icongyou.enterprise.data_aggregation.service.DataAggregationService;
import com.icongyou.enterprise.talent_analysis.entity.dto.StudentFeatureContext;
import com.icongyou.enterprise.talent_analysis.service.impl.StudentFeatureExtractor;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;

/**
 * 学生特征提取器测试
 */
@ExtendWith(MockitoExtension.class)
@DisplayName("学生特征提取器测试")
class StudentFeatureExtractorTest {

    @Mock
    private DataAggregationService dataAggregationService;

    @InjectMocks
    private StudentFeatureExtractor extractor;

    private static final String STUDENT_ID = "660e8400-e29b-41d4-a716-446655440105";
    private static final String COURSE_ID = "course-1";
    private static final String ASSIGNMENT_ID = "assignment-1";
    private static final String SUBMISSION_ID = "submission-1";
    private static final String TEAM_ID = "team-1";

    @BeforeEach
    void setUp() {
        // 基础设置
    }

    @Test
    @DisplayName("extractFeatures - 学生不存在返回空上下文")
    void testExtractFeatures_StudentNotFound() {
        // Arrange
        when(dataAggregationService.getStudentById(STUDENT_ID)).thenReturn(null);

        // Act
        StudentFeatureContext context = extractor.extractFeatures(STUDENT_ID);

        // Assert
        assertNotNull(context);
        assertNull(context.getStudentId());
        verify(dataAggregationService).getStudentById(STUDENT_ID);
        verify(dataAggregationService, never()).getStudentRawMetrics(anyString(), anyDouble(), anyInt(), anyInt());
    }

    @Test
    @DisplayName("extractFeatures - 提取完整特征")
    void testExtractFeatures_Complete() {
        // Arrange
        UserEntity student = createStudent();
        Map<String, Object> rawMetrics = createRawMetrics();
        List<CourseStudentEntity> courses = Collections.singletonList(createCourse());
        List<AssignmentStudentEntity> assignments = Collections.singletonList(createAssignmentStudent());
        List<SubmissionEntity> submissions = Collections.singletonList(createSubmission());
        List<GradeEntity> grades = Collections.singletonList(createGrade());
        List<GradeEntity> comments = Collections.singletonList(createComment());
        List<TeamMemberEntity> teams = Collections.singletonList(createTeamMember());
        TeamEntity team = createTeam();

        when(dataAggregationService.getStudentById(STUDENT_ID)).thenReturn(student);
        when(dataAggregationService.getStudentRawMetrics(eq(STUDENT_ID), anyDouble(), anyInt(), anyInt()))
            .thenReturn(rawMetrics);
        when(dataAggregationService.getStudentCourse(STUDENT_ID)).thenReturn(courses);
        when(dataAggregationService.getStudentAssignmentScore(STUDENT_ID, COURSE_ID)).thenReturn(assignments);
        when(dataAggregationService.getStudentSubmission(STUDENT_ID, ASSIGNMENT_ID)).thenReturn(submissions);
        when(dataAggregationService.getStudentGrade(SUBMISSION_ID)).thenReturn(grades);
        when(dataAggregationService.getTeacherComment(STUDENT_ID)).thenReturn(comments);
        when(dataAggregationService.getStudentTeam(STUDENT_ID)).thenReturn(teams);
        when(dataAggregationService.getTeamById(TEAM_ID)).thenReturn(team);

        // Act
        StudentFeatureContext context = extractor.extractFeatures(STUDENT_ID);

        // Assert
        assertNotNull(context);
        assertEquals(STUDENT_ID, context.getStudentId());
        assertEquals("孙七", context.getStudentName());
        assertEquals("计算机科学与技术", context.getMajor());
        assertNotNull(context.getNumericMetrics());
        assertTrue(context.getAssignments().size() > 0);
        assertTrue(context.getTeacherComments().size() > 0);
        assertTrue(context.getTeamExperiences().size() > 0);
        assertNotNull(context.getLearningBehavior());
        assertNotNull(context.getSummary());
    }

    @Test
    @DisplayName("extractFeatures - 基础信息提取")
    void testExtractFeatures_BasicInfo() {
        // Arrange
        UserEntity student = createStudent();
        when(dataAggregationService.getStudentById(STUDENT_ID)).thenReturn(student);
        when(dataAggregationService.getStudentRawMetrics(anyString(), anyDouble(), anyInt(), anyInt()))
            .thenReturn(new HashMap<>());
        when(dataAggregationService.getStudentCourse(anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationService.getTeacherComment(anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationService.getStudentTeam(anyString())).thenReturn(Collections.emptyList());

        // Act
        StudentFeatureContext context = extractor.extractFeatures(STUDENT_ID);

        // Assert
        assertEquals(STUDENT_ID, context.getStudentId());
        assertEquals("孙七", context.getStudentName());
        assertEquals("计算机科学与技术", context.getMajor());
        assertEquals("2021级计算机1班", context.getClassName());
    }

    @Test
    @DisplayName("extractFeatures - 数值指标提取")
    void testExtractFeatures_NumericMetrics() {
        // Arrange
        UserEntity student = createStudent();
        Map<String, Object> metrics = createRawMetrics();
        
        when(dataAggregationService.getStudentById(STUDENT_ID)).thenReturn(student);
        when(dataAggregationService.getStudentRawMetrics(STUDENT_ID, 0.6, 120, 7)).thenReturn(metrics);
        when(dataAggregationService.getStudentCourse(anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationService.getTeacherComment(anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationService.getStudentTeam(anyString())).thenReturn(Collections.emptyList());

        // Act
        StudentFeatureContext context = extractor.extractFeatures(STUDENT_ID);

        // Assert
        assertNotNull(context.getNumericMetrics());
        assertEquals(85.0, context.getNumericMetrics().get("avg_course_score"));
        assertEquals(0.9, context.getNumericMetrics().get("on_time_submission_rate"));
    }

    @Test
    @DisplayName("extractFeatures - 教师评价提取")
    void testExtractFeatures_TeacherComments() {
        // Arrange
        UserEntity student = createStudent();
        List<GradeEntity> comments = Arrays.asList(
            createComment("优秀作品，设计合理", 95.0, true),
            createComment("需要改进", 70.0, false)
        );
        
        when(dataAggregationService.getStudentById(STUDENT_ID)).thenReturn(student);
        when(dataAggregationService.getStudentRawMetrics(anyString(), anyDouble(), anyInt(), anyInt()))
            .thenReturn(new HashMap<>());
        when(dataAggregationService.getStudentCourse(anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationService.getTeacherComment(STUDENT_ID)).thenReturn(comments);
        when(dataAggregationService.getStudentTeam(anyString())).thenReturn(Collections.emptyList());

        // Act
        StudentFeatureContext context = extractor.extractFeatures(STUDENT_ID);

        // Assert
        assertEquals(2, context.getTeacherComments().size());
        
        StudentFeatureContext.TeacherComment tc1 = context.getTeacherComments().get(0);
        assertEquals("优秀作品，设计合理", tc1.getCommentText());
        assertEquals(new BigDecimal("95.0"), tc1.getScore());
        assertTrue(tc1.getIsRecommended());
        
        StudentFeatureContext.TeacherComment tc2 = context.getTeacherComments().get(1);
        assertEquals("需要改进", tc2.getCommentText());
        assertFalse(tc2.getIsRecommended());
    }

    @Test
    @DisplayName("extractFeatures - 团队经历提取")
    void testExtractFeatures_TeamExperience() {
        // Arrange
        UserEntity student = createStudent();
        TeamMemberEntity teamMember = createTeamMember();
        TeamEntity team = createTeam();
        
        when(dataAggregationService.getStudentById(STUDENT_ID)).thenReturn(student);
        when(dataAggregationService.getStudentRawMetrics(anyString(), anyDouble(), anyInt(), anyInt()))
            .thenReturn(new HashMap<>());
        when(dataAggregationService.getStudentCourse(anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationService.getTeacherComment(anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationService.getStudentTeam(STUDENT_ID))
            .thenReturn(Collections.singletonList(teamMember));
        when(dataAggregationService.getTeamById(TEAM_ID)).thenReturn(team);

        // Act
        StudentFeatureContext context = extractor.extractFeatures(STUDENT_ID);

        // Assert
        assertEquals(1, context.getTeamExperiences().size());
        
        StudentFeatureContext.TeamExperience te = context.getTeamExperiences().get(0);
        assertEquals("开发小组A", te.getTeamName());
        assertEquals(new BigDecimal("88.0"), te.getTeamScore());
        assertEquals(3, te.getTeamRanking());
    }

    @Test
    @DisplayName("extractFeatures - 学习行为统计")
    void testExtractFeatures_LearningBehavior() {
        // Arrange
        setupCompleteData();

        // Act
        StudentFeatureContext context = extractor.extractFeatures(STUDENT_ID);

        // Assert
        StudentFeatureContext.LearningBehavior lb = context.getLearningBehavior();
        assertNotNull(lb);
        assertTrue(lb.getTotalSubmissions() > 0);
        assertTrue(lb.getOnTimeSubmissions() >= 0);
        assertTrue(lb.getLateSubmissions() >= 0);
    }

    @Test
    @DisplayName("extractFeatures - 无课程数据")
    void testExtractFeatures_NoCourses() {
        // Arrange
        UserEntity student = createStudent();
        when(dataAggregationService.getStudentById(STUDENT_ID)).thenReturn(student);
        when(dataAggregationService.getStudentRawMetrics(anyString(), anyDouble(), anyInt(), anyInt()))
            .thenReturn(new HashMap<>());
        when(dataAggregationService.getStudentCourse(STUDENT_ID)).thenReturn(Collections.emptyList());
        when(dataAggregationService.getTeacherComment(anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationService.getStudentTeam(anyString())).thenReturn(Collections.emptyList());

        // Act
        StudentFeatureContext context = extractor.extractFeatures(STUDENT_ID);

        // Assert
        assertTrue(context.getAssignments().isEmpty());
        assertEquals(0, context.getLearningBehavior().getTotalSubmissions());
    }

    // ==================== Helper Methods ====================

    private UserEntity createStudent() {
        UserEntity student = new UserEntity();
        student.setId(STUDENT_ID);
        student.setRealName("孙七");
        student.setMajor("计算机科学与技术");
        student.setClassName("2021级计算机1班");
        return student;
    }

    private Map<String, Object> createRawMetrics() {
        Map<String, Object> metrics = new HashMap<>();
        metrics.put("avg_course_score", 85.0);
        metrics.put("avg_assignment_score", 90.0);
        metrics.put("on_time_submission_rate", 0.9);
        metrics.put("assignment_pass_rate", 0.95);
        return metrics;
    }

    private CourseStudentEntity createCourse() {
        CourseStudentEntity course = new CourseStudentEntity();
        course.setCourseId(COURSE_ID);
        course.setStudentId(STUDENT_ID);
        course.setScore(new BigDecimal("85.0"));
        return course;
    }

    private AssignmentStudentEntity createAssignmentStudent() {
        AssignmentStudentEntity as = new AssignmentStudentEntity();
        as.setAssignmentId(ASSIGNMENT_ID);
        as.setStudentId(STUDENT_ID);
        as.setTeamId(TEAM_ID);
        as.setAssignedScore(new BigDecimal("90.0"));
        as.setStatus(2); // 已批改
        return as;
    }

    private SubmissionEntity createSubmission() {
        SubmissionEntity sub = new SubmissionEntity();
        sub.setSubmissionId(SUBMISSION_ID);
        sub.setAssignmentId(ASSIGNMENT_ID);
        sub.setStudentId(STUDENT_ID);
        sub.setTeamId(TEAM_ID);
        sub.setActualDuration(120);
        sub.setIsLate(0);
        sub.setLikeCount(5);
        sub.setFavoriteCount(3);
        
        // 设置贡献率
        SubmissionEntity.ContributionItem item = new SubmissionEntity.ContributionItem();
        item.setStudentId(STUDENT_ID);
        item.setRate(new BigDecimal("25.0"));
        sub.setContributionRate(Collections.singletonList(item));
        
        return sub;
    }

    private GradeEntity createGrade() {
        GradeEntity grade = new GradeEntity();
        grade.setSubmissionId(SUBMISSION_ID);
        grade.setFinalScore(new BigDecimal("88.0"));
        grade.setTextComment("完成良好");
        grade.setIsTeacherRecommended(0);
        return grade;
    }

    private GradeEntity createComment(String text, Double score, boolean recommended) {
        GradeEntity grade = new GradeEntity();
        grade.setTextComment(text);
        grade.setFinalScore(score != null ? new BigDecimal(score.toString()) : null);
        grade.setIsTeacherRecommended(recommended ? 1 : 0);
        return grade;
    }

    private GradeEntity createComment() {
        return createComment("优秀作品", 95.0, true);
    }

    private TeamMemberEntity createTeamMember() {
        TeamMemberEntity tm = new TeamMemberEntity();
        tm.setTeamId(TEAM_ID);
        tm.setStudentId(STUDENT_ID);
        return tm;
    }

    private TeamEntity createTeam() {
        TeamEntity team = new TeamEntity();
        team.setTeamId(TEAM_ID);
        team.setTeamName("开发小组A");
        team.setCurrentScore(new BigDecimal("88.0"));
        team.setRanking(3);
        return team;
    }

    private void setupCompleteData() {
        UserEntity student = createStudent();
        Map<String, Object> rawMetrics = createRawMetrics();
        List<CourseStudentEntity> courses = Collections.singletonList(createCourse());
        List<AssignmentStudentEntity> assignments = Collections.singletonList(createAssignmentStudent());
        List<SubmissionEntity> submissions = Collections.singletonList(createSubmission());
        List<GradeEntity> grades = Collections.singletonList(createGrade());

        when(dataAggregationService.getStudentById(STUDENT_ID)).thenReturn(student);
        when(dataAggregationService.getStudentRawMetrics(anyString(), anyDouble(), anyInt(), anyInt()))
            .thenReturn(rawMetrics);
        when(dataAggregationService.getStudentCourse(STUDENT_ID)).thenReturn(courses);
        when(dataAggregationService.getStudentAssignmentScore(STUDENT_ID, COURSE_ID)).thenReturn(assignments);
        when(dataAggregationService.getStudentSubmission(STUDENT_ID, ASSIGNMENT_ID)).thenReturn(submissions);
        when(dataAggregationService.getStudentGrade(SUBMISSION_ID)).thenReturn(grades);
        when(dataAggregationService.getTeacherComment(anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationService.getStudentTeam(anyString())).thenReturn(Collections.emptyList());
    }
}
